package com.lzyyj.gmis.base.dao;

import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.lzyyj.common.BeanUtilsExt;

/**
 * 持久化处理助手
 * @author Lzyyj
 *
 */
public class PersistenceHelper {
	
	private static final Log log = LogFactory.getLog(PersistenceHelper.class);

	/**
	 * 按属性列表加载实体属性
	 * @param list					实体列表
	 * @param entityClass			实体对象类型
	 * @param propertyList			属性列表
	 * @param propertyValueCache	外键缓存，避免重复加载
	 * @param baseDao				实体对象Dao
	 * @return
	 * @throws Exception
	 */
	public static Map<Class<?>, Map<Serializable, Object>> loadProperties(Collection<Object> list, Class<?> entityClass, String propertyList, Map<Class<?>, Map<Serializable, Object>> propertyValueCache, IBaseDao<Object, Serializable> baseDao) throws Exception {
		
		if (propertyValueCache == null){
			propertyValueCache = new HashMap<Class<?>, Map<Serializable, Object>>();
		}
		
		Map<Serializable, Object> entityCache = null; 
		if (propertyValueCache.containsKey(entityClass)){
			entityCache = propertyValueCache.get(entityClass);
		}
		if (entityCache==null){
			entityCache = new HashMap<Serializable, Object>();
			propertyValueCache.put(entityClass, new HashMap<Serializable, Object>());
		}
		
		if (list!=null){
			// 外键属性缓存
			for(Object entityPo:list){
				Serializable pkId = baseDao.getPK(entityPo);
				if (!entityCache.containsKey(pkId)){
					entityCache.put(pkId, entityPo);
				}
				
				loadProperties(entityPo, entityClass, propertyList, propertyValueCache, baseDao);
			}
		}
		
		return propertyValueCache;
	}

	/**
	 * 按属性列表加载实体属性
	 * @param entityPo				实体对象
	 * @param entityClass			实体对象类型
	 * @param propertyList			属性列表
	 * @param propertyValueCache	外键缓存，避免重复加载
	 * @param baseDao				实体对象Dao
	 * @return
	 * @throws Exception
	 */
	public static Map<Class<?>, Map<Serializable, Object>> loadProperties(Object entityPo, Class<?> entityClass, String propertyList, Map<Class<?>, Map<Serializable, Object>> propertyValueCache, IBaseDao<Object, Serializable> baseDao) throws Exception {

		if (propertyValueCache == null){
			propertyValueCache = new HashMap<Class<?>, Map<Serializable, Object>>();
		}
		
		Map<Serializable, Object> entityCache = null; 
		if (propertyValueCache.containsKey(entityClass)){
			entityCache = propertyValueCache.get(entityClass);
		}
		if (entityCache==null){
			entityCache = new HashMap<Serializable, Object>();
			propertyValueCache.put(entityClass, new HashMap<Serializable, Object>());
		}
		Serializable id = baseDao.getPK(entityPo);
		if (!entityCache.containsKey(id)){
			entityCache.put(id, entityPo);
		}
		
		Map<String, String> propertyMap = new HashMap<String, String>();
		if (entityPo!=null&&propertyList!=null&&propertyList.length()>0){
			parseNextPropertyList(entityPo, propertyList, propertyMap, baseDao);
			for(Entry<String, String> pn: propertyMap.entrySet()){
				String propertyName = pn.getKey();
				String nextPropertyList = pn.getValue();
				
				boolean propertyIsCollection = false;
				Class<?> propertyClass = BeanUtilsExt.getPropertyType(entityClass, propertyName);
				Class<?> propertyMemberClass;
				if (Collection.class.isAssignableFrom(propertyClass)){
					propertyIsCollection = true;
					propertyMemberClass = BeanUtilsExt.getMemberType(entityClass, propertyName);
				}else{
					propertyMemberClass = propertyClass;
				}
				
				IBaseDao<Object, Serializable> dao = (IBaseDao<Object, Serializable>)baseDao.getBaseDao(propertyMemberClass);
				Object propertyValue = BeanUtilsExt.getPropertyValue(entityPo, propertyName);
				Map<Serializable, Object> cache = null;
				if (propertyValueCache.containsKey(propertyMemberClass)){
					cache = propertyValueCache.get(propertyMemberClass);
				}
				if (cache == null){
					cache = new HashMap<Serializable, Object>();
					propertyValueCache.put(propertyMemberClass, cache);
				}

				if (baseDao.isPersistentProperty(entityClass, propertyName)){
					// 是持久化外键对象，直接递归处理下一级属性
					if(propertyValue!=null){
						if (propertyIsCollection&&((Collection<Object>)propertyValue).size()>0){
							loadProperties((Collection<Object>)propertyValue, propertyMemberClass, nextPropertyList, propertyValueCache, dao);
						}else{
							loadProperties(propertyValue, propertyMemberClass, nextPropertyList, propertyValueCache, dao);
						}
					}
				}else{
					// 非持久化属性，需要映射到持久化外键以获取目标外键对象
					// 最终有效的持久化属性
					String persistentPropertyName = null;
					// 最终有效持久化属性类型，要么是目标外键对象的主键类型，要么就是目标外键对象类型
					Class<?> persistentPropertyClass = null;
					Class<?> persistentPropertyMemberClass = null;
					Object persistentPropertyValue = null;
					boolean persistentPropertyIsCollection = false;

					// 外键对象上反向关联的属性名
					String fkEntityRelationPropertyName = null;
					// 外键对象关联属性是否是集合
					boolean fkEntityRelationPropertyIsCollection = false;

					Entry<String, Class<?>> entry = PersistenceHelper.findForeignKey(propertyName, propertyMemberClass, baseDao.getForeignKeyMap());
					if (entry!=null){
						String[] keyStr = entry.getKey().split(":");
						if (keyStr.length>1){
							if (keyStr.length>2){
								fkEntityRelationPropertyName = keyStr[2];
							}
							String[] propertyPath = keyStr[1].split("\\.");
							// 初始化循环迭代变量, 以默认实体类为起始
							Class<?> pkEntityClass = entityClass;
							Class<?> pkEntityMemberClass = entityClass;
							Object pkEntity = entityPo;
							boolean pkIsCollection = false;
							boolean fkIsCollection = false;
							IBaseDao<Object, Serializable> rkDao = (IBaseDao<Object, Serializable>)baseDao;
							
							String currPropertyName;
							String currPersistentProperty;
							Object fkEntity;
							for(int i=0;i<propertyPath.length;i++){
								currPropertyName = propertyPath[i];
								
								currPersistentProperty = currPropertyName;
								Class<?> fkEntityClass = BeanUtilsExt.getPropertyType(pkEntityMemberClass, currPersistentProperty);
								Class<?> fkEntityMemberClass;
								
								if (Collection.class.isAssignableFrom(fkEntityClass)){
									fkIsCollection = true;
									fkEntityMemberClass = BeanUtilsExt.getMemberType(pkEntityClass, currPersistentProperty);
								}else{
									fkEntityMemberClass = fkEntityClass;
								}
								if (i<propertyPath.length-1){
									// 中间级，通常应该是一个关联表对象,如 DeptUsers.deptId 中的 DeptUsers, 
									// 但也有可能是中间及对象 如 Depart.parent.rootDept

									// 属性可能不是真正的持久化属性
									if (!baseDao.isPersistentProperty(pkEntityMemberClass, currPropertyName)){
										// 真不是真正的持久化属性，那就读取一下
										if (fkIsCollection){
											// 真不是真正的持久化属性,而且还是集合, user.userOrgs.xxx
											Serializable pkId = rkDao.getPK(pkEntity);
											rkDao = (IBaseDao<Object, Serializable>)baseDao.getBaseDao(fkEntityMemberClass);
											String fkPropertyName = PersistenceHelper.findForeignKey(currPropertyName, pkEntityMemberClass, rkDao.getForeignKeyMap()).getKey().split(":")[1];
											List<Object> list = rkDao.findByProperty(fkPropertyName, pkId, "");
											for(Object obj:list){
												((Collection<Object>)persistentPropertyValue).add(obj);
											}
										}else{
											// 真不是真正的持久化属性,但不是集合, 如 dept.parent.xxx
											Serializable pkId = rkDao.getPK(pkEntity);
											rkDao = (IBaseDao<Object, Serializable>)baseDao.getBaseDao(fkEntityMemberClass);
											String fkPropertyName = PersistenceHelper.findForeignKey(currPropertyName, pkEntityMemberClass, rkDao.getForeignKeyMap()).getKey().split(":")[1];
											List<Object> list = rkDao.findByProperty(fkPropertyName, pkId, "");
											for(Object obj:list){
												((Collection<Object>)persistentPropertyValue).add(obj);
											}
										}
									}
									
									if (pkIsCollection){
										// 前一级是集合
										List<Object> list = new ArrayList<Object>();
										for(Object pkEntityItem:(Collection)pkEntity){
											if (fkIsCollection){
												// 是集合
												fkEntity = BeanUtilsExt.getPropertyValue(pkEntityItem, currPersistentProperty);
												for(Object fkEntityItem:(Collection)fkEntity){
													list.add(fkEntityItem);
												}
											}else{
												// 不是集合
												fkEntity = BeanUtilsExt.getPropertyValue(pkEntityItem, currPersistentProperty);
												list.add(fkEntity);
											}
										}
										fkEntity = list;
										fkIsCollection = true;
									}else{
										// 源属性不是集合,不用做太多处理了。
										fkEntity = BeanUtilsExt.getPropertyValue(pkEntity, currPersistentProperty);
									}

									// 中间级映射处理完成，剩最后一级未处理
									
									// 循环控制变量迭代
									pkEntityClass = fkEntityClass;
									pkEntityMemberClass = fkEntityMemberClass;
									pkEntity = fkEntity;
									pkIsCollection = fkIsCollection;
									
									fkEntityClass = null;
									fkEntityMemberClass = null;
									fkEntity = null;
									fkIsCollection = false;
								}else{
									if (pkIsCollection){
										// 前一级是集合
										persistentPropertyValue = pkEntity;
										persistentPropertyIsCollection = true;
									}else{
										// 前不是集合
										fkEntity = BeanUtilsExt.getPropertyValue(pkEntity, currPersistentProperty);
										persistentPropertyValue = fkEntity;
										persistentPropertyIsCollection = fkIsCollection;
									}
									// 末级，目标类型应该是最终类型,或是其主键类型
									persistentPropertyName = currPersistentProperty;
									persistentPropertyClass = fkEntityMemberClass;
									persistentPropertyMemberClass = fkEntityMemberClass;
								}
							}
							// 持久化映射处理完毕
						}
					}
					
					// 非持久化属性，需要映射到持久化外键键值或者持久化外键对象
					// 持久化映射处理完毕, 看看结果
					if (persistentPropertyName!=null){
						// 有有效的持久化属性映射
						if(persistentPropertyMemberClass.equals(propertyMemberClass)){
							// 映射的末级如果目标类型，必须是持久化类型，否则就应该映射成他的外键键值
							if (persistentPropertyIsCollection){
								// 是集合
							}else{
								// 不是集合
								if (propertyIsCollection){
									// 源属性是集合
								}else{
									// 源属性不是集合
									BeanUtilsExt.setPropertyValue(entityPo, propertyName, persistentPropertyValue);
								}
							}
						}else{
							// 映射的持久化属性不是目标类型，那就应该是外键对象的主键键值
							// 如果持久化属性是集合而要被赋值的目标属性不是集合，看看是否仅有唯一的持久化对象可选
							if (persistentPropertyIsCollection&&!propertyIsCollection){
								if (((Collection)persistentPropertyValue).size()==1){
									Object persistentPropertyMemberValue = null;
									for(Object obj:((Collection)persistentPropertyValue)){
										persistentPropertyMemberValue = obj;
										break;
									}
									persistentPropertyValue = BeanUtilsExt.getPropertyValue(persistentPropertyMemberValue, persistentPropertyName);
									persistentPropertyClass = persistentPropertyMemberClass;
									persistentPropertyIsCollection = false;
								}
							}
							
							if (persistentPropertyIsCollection){
								// 持久化属性是集合
								if (propertyIsCollection){
									// 持久化属性是集合，要被赋值的目标属性也是集合，先看看目标集合准备好没
									if (propertyValue==null){
										// 目标集合没准备好，准备一个，
										propertyValue = new ArrayList<Object>();
										BeanUtilsExt.setPropertyValue(entityPo, propertyName, propertyValue);
									}else{
										// 准备好了的，但也该清空一下
										((Collection<Object>)propertyValue).clear();
									}
									// 可以目标属性里装了，有的话
									
									// 如果有外键对象上反向关联的属性名，并且它也是一个存在的属性的话，即有反向关联
									boolean haveReverseRelevance = fkEntityRelationPropertyName!=null&& BeanUtilsExt.isProperty(propertyMemberClass, fkEntityRelationPropertyName);
									if (haveReverseRelevance){
										Class<?> aClass = BeanUtilsExt.getPropertyType(propertyMemberClass, fkEntityRelationPropertyName);
										if (Collection.class.isAssignableFrom(aClass)||!entityClass.equals(aClass)){
											haveReverseRelevance = false;
										}
									}
									for(Object rItem:(Collection<Object>)persistentPropertyValue){
										Serializable fkId = (Serializable) BeanUtilsExt.getPropertyValue(rItem, persistentPropertyName);
										
										Object fkEntity = dao.getById(fkId, nextPropertyList);
										if (fkEntity!=null){
											if (haveReverseRelevance){
												BeanUtilsExt.setPropertyValue(fkEntity, fkEntityRelationPropertyName, entityPo);
											}
											((Collection<Object>)propertyValue).add(fkEntity);
										}
									}
								}else{
									// 持久化属性是集合，而要被赋值的目标属性不是集合，需要一个取舍方法
									if (((Collection)persistentPropertyValue).size()==1){
										
									}else{
										
									}
									log.warn("源属性不是集合，但缺映射到了集合上，怎么取舍呢！？");
									throw new Exception("源属性不是集合，但缺映射到了集合上，怎么取舍呢！？");
								}
							}else{
								// 持久化属性，即源，不是集合

								if (propertyIsCollection){
									// 目标属性是集合
									if (propertyValue==null){
										propertyValue = new ArrayList<Object>();
										BeanUtilsExt.setPropertyValue(entityPo, propertyName, persistentPropertyValue);
									}else{
										((Collection<Object>)propertyValue).clear();
									}
									Serializable pkId = (Serializable)(baseDao.getPK(entityPo));
									List<Object> list = (List<Object>)dao.findByProperty(persistentPropertyName, pkId, null);
									for(Object obj:list){
										Serializable fkId = dao.getPK(obj);
										if (cache.containsKey(fkId)){
											obj = cache.get(fkId);
										}else{
											cache.put(fkId, obj);
										}
										((Collection<Object>)propertyValue).add(obj);
									}
								}else{
									Serializable fkId = (Serializable)persistentPropertyValue;
									Object fkObj;
									if (cache.containsKey(fkId)){
										fkObj = cache.get(fkId);
									}else{
										fkObj = (Object)dao.getById(fkId, nextPropertyList);
										if (fkObj!=null){
											cache.put(fkId, fkObj);
										}
									}
									// 源属性不是集合
									BeanUtilsExt.setProperty(entityPo, propertyName, fkObj);
								}
							}
						}
					}else{
						log.error("没有解析出有效的持久化属性，");
						throw new Exception("没有解析出有效的持久化属性，");
					}
					// 非持久化属性，需要映射到持久化外键以获取目标外键对象，处理完毕
				}
			}
		}
		
		return propertyValueCache;
	}

	private static void parseNextPropertyList(Object entityPo, String propertyList, Map<String, String> propertyMap, IBaseDao<?,?> baseDao) throws Exception {
		
		Class<?> entityClass = baseDao.getEntityClass(); 
		for(String property:propertyList.split(",")){
			String[] propertyPath = property.split("\\.");
			if (propertyPath.length>0){
				String propertyName = propertyPath[0];
				Object propertyValue;
				Class<?> propertyValueClass;
				if (BeanUtilsExt.isProperty(entityClass, propertyName)){
					// 是一个属性
					propertyValueClass = BeanUtilsExt.getPropertyType(entityClass, propertyName);
					if (Collection.class.isAssignableFrom(propertyValueClass)){
						propertyValueClass = BeanUtilsExt.getMemberType(entityClass, propertyName);
					}
					if (baseDao.isEntity(propertyValueClass)){
						// 是实体对象，应该是外键对象
						String map = null;
						if (propertyMap.containsKey(propertyName)){
							// 已有过
							map = propertyMap.get(propertyName);
						}else{
							// 没有过，占个位置
							propertyMap.put(propertyName, null);
						}
						
						if (propertyPath.length>1){
							String nextProperty = null;
							for(int i=1;i<propertyPath.length;i++){
								if (nextProperty==null){
									nextProperty = "";
								}else{
									nextProperty += ".";
								}
								nextProperty += propertyPath[i];
							}
							if (map==null){
								map = "";
								propertyMap.put(propertyName, map);
							}
							if (!(","+map+",").contains(","+nextProperty+",")){
								if (map.length()>0){
									map += ",";
								}
								map +=nextProperty;
								propertyMap.put(propertyName, map);
							}
						}

					}else{
						// 不是实体, 
						if (baseDao.isPersistentProperty(propertyName)){
							// 那就应该是基本的数据类型了
							propertyValue = PropertyUtils.getProperty(entityPo, propertyName);
							log.debug("是持久化属性，强制加载一下："+propertyValue);
						}else{
							log.debug("非持久化属性，非实体对象，这是什么样的情况？！");
						}
					}
				}
			}
		}
	}

	/**
	 * 属性复制
	 * @param srcEntityVo
	 * @param tarEntityPo
	 * @param copyPropertyList
	 * @param persistent 针对外键引用，是否需要进行持久化转换，主要用于getNew
	 * @throws Exception 
	 */
	public static <T, PK extends Serializable, T1> Map<String, String> copyProperties(T srcEntityVo, T tarEntityPo, String copyPropertyList, boolean persistent, IBaseDao<T, PK> baseDao) throws Exception {
		
		// 准备用于合并可能出现的公共关联表，好像没有用它
		Map<String, String> relevanceMap = new HashMap<String, String>();
		
		if (srcEntityVo!=tarEntityPo){
			if (copyPropertyList == null) {
				copyPropertyList = baseDao.getPropertyList();
			}
			
			// 先复制简单属性，并过滤出外键属性及其属性列表
			Map<String, String> propertyMap = firstCopySimpleProperties(srcEntityVo, tarEntityPo, copyPropertyList, baseDao);
			
			// 现在开始处理外键对象
			for(Entry<String, String> en: propertyMap.entrySet()){
				// 本级外键属性
				String propertyName = en.getKey();
				// 下一级外键对象需要处理的属性列表
				String nextPropertyList = en.getValue();
				
				copyFkProperty(srcEntityVo, tarEntityPo, propertyName, nextPropertyList, persistent, baseDao, relevanceMap);
			}
		}
		
		return relevanceMap;
	}

	/**
	 * 复制外键属性
	 * @param srcEntityVo		源实体值对象
	 * @param tarEntityPo		目标实体持久化对象
	 * @param propertyName		外键属性名
	 * @param nextPropertyList	要处理的外键属性列表
	 * @param persistent		是否必须进行持久化处理
	 * @param baseDao			实体Dao
	 * @param relevanceMap		引用表
	 * @throws Exception
	 */
	private static <T, T1, PK extends Serializable> void copyFkProperty(
			T srcEntityVo, T tarEntityPo, String propertyName, String nextPropertyList, 
			boolean persistent, IBaseDao<T, PK> baseDao, Map<String, String> relevanceMap)
			throws Exception {
		
		// 主键实体类类型
		Class<T> entityClass = baseDao.getEntityClass();
		
		// 属性类型
		Class<?> propertyClass = (Class<?>) BeanUtilsExt.getPropertyType(entityClass, propertyName);
		
		// 属性成员类型
		Class<T1> fkEntityClass;
		
		// 属性是否是集合
		boolean propertyIsCollection = false;
		if (Collection.class.isAssignableFrom(propertyClass)){
			fkEntityClass = (Class<T1>) BeanUtilsExt.getMemberType(entityClass, propertyName);
			propertyIsCollection = true;
		}else{
			fkEntityClass = (Class<T1>)propertyClass;
		}
		
		Object srcFkPropertyValue = PropertyUtils.getProperty(srcEntityVo, propertyName);
		Object tarFkPropertyValue = PropertyUtils.getProperty(tarEntityPo, propertyName);

		Class<?> persistenceEntityClass;				// 最终的持久化对象
		Object persistenceEntity;						// 最终的持久化对象
		String persistencePropertyName;					// 持久化属性名

		// 外键属性是否是持久化属性
		if (baseDao.isPersistentProperty(entityClass, propertyName)){
			// 外键属性是经持久化属性
			persistenceEntityClass = entityClass;		// 最终的持久化实体对象类型
			persistenceEntity = tarEntityPo;			// 最终的持久化实体对象
			persistencePropertyName = propertyName;		// 最终的持久化属性名
		}else{
			// 外键属性非持久化属性，获取映射的最终持久化属性参数
			Map<String, Object> result = getPersistenceProperty(srcEntityVo, tarEntityPo, propertyName,
					baseDao, propertyClass, fkEntityClass, propertyIsCollection, relevanceMap);
			persistenceEntityClass = (Class<?>)result.get("persistenceEntityClass");		// 最终的持久化实体对象类型
			persistenceEntity = result.get("persistenceEntity");							// 最终的持久化实体对象
			persistencePropertyName = (String)result.get("persistencePropertyName");		// 最终的持久化属性名
		}
		
		Class<?> persistencePropertyClass = BeanUtilsExt.getPropertyType(persistenceEntityClass, persistencePropertyName);
		Class<?> persistencePropertyMemberClass = persistencePropertyClass;					// 持久化属性成员类型
		if (Collection.class.isAssignableFrom(persistencePropertyClass)){
			persistencePropertyMemberClass = BeanUtilsExt.getMemberType(persistenceEntityClass, persistencePropertyName);	// 持久化属性成员类型
		}
		Object persistencePropertyValue = BeanUtilsExt.getPropertyValue(persistenceEntity, persistencePropertyName);		// 持久化属性值

		IBaseDao<Object, Serializable> persistenceEntityDao = (IBaseDao<Object, Serializable>)baseDao.getBaseDao(persistenceEntityClass);
		IBaseDao<Object, Serializable> fkDao = (IBaseDao<Object, Serializable>)baseDao.getBaseDao(fkEntityClass);
		
		// 外键属性是否是持久化属性
		if (baseDao.isPersistentProperty(entityClass, propertyName)){
			// 外键属性是持久化属性，那么是否是集合呢，即是 department.parent, 还是 department.users 呢
			if (propertyIsCollection){
				// 该外键属性是持久化属性，而且是集合，如 department.users
				// 如果目标对象存在，简单的递归复制即可
				if (srcFkPropertyValue==null||((Collection)srcFkPropertyValue).size()==0){
					log.debug("源外键对象为空，清空目标外键集合");
					if (tarFkPropertyValue!=null&&((Collection)tarFkPropertyValue).size()>0){
						((Collection)tarFkPropertyValue).clear();
					}
				}else{
					// 源外键对象不为空
					if (tarFkPropertyValue==null){
						BeanUtilsExt.setPropertyValue(tarFkPropertyValue, propertyName, new ArrayList<Object>());
					}
					
					// 获取外键对象的主键名称
					String fkName = baseDao.getPkNameByEntityClass(fkEntityClass);
					List<Object> newFkEntities = new ArrayList<Object>();
					Map<Serializable, Object> fkEntityMap = new HashMap<Serializable, Object>();
					List<Object> removeList = new ArrayList<Object>();
					for(Object obj2:(Collection)tarFkPropertyValue){
						Serializable tarPkId = (Serializable) BeanUtilsExt.getPropertyValue(obj2, fkName);
						fkEntityMap.put(tarPkId, obj2);
						removeList.add(obj2);
					}
					
					// 遍历源外键对象，添加新建的，更新已有的，移除没有的（未实现，调试中）
					for(Object srcFkPropertyValue2:(Collection)srcFkPropertyValue){
						Serializable fkId = (Serializable) BeanUtilsExt.getPropertyValue(srcFkPropertyValue2, fkName);
						
						if (fkId==null){
							// 需新建的外键对象
							newFkEntities.add(srcFkPropertyValue2);
						}else{
							// 不需新建，但可能需递归处理其属性
							Object tarPropertyMemberValue = null;
							if (fkEntityMap.containsKey(fkId)){
								// 如果目标属性中存在，级联更新
								tarPropertyMemberValue = fkEntityMap.get(fkId);
								// 不需移除
								removeList.remove(tarPropertyMemberValue);
								// 目标对象存在，简单的递归复制即可
								copyProperties(srcFkPropertyValue2, tarPropertyMemberValue, nextPropertyList, persistent, fkDao);
							}
						}
					}
					// 移除没有的
					for(Object obj:removeList){
						((Collection)tarFkPropertyValue).remove(obj);
						// 注意：是否应在对方属性上处理呢？
					}
					// 添加新建的
					for(Object obj:newFkEntities){
						((Collection)tarFkPropertyValue).add(obj);
						// 注意：是否应在对方属性上处理呢？
					}
				}
			}else{
				// 该外键属性是持久化属性，不是集合，如 department.parent
				// 如果目标对象存在，简单的递归复制即可
				if (srcFkPropertyValue==null){
					log.debug("源外键对象为空，不做更多处理！");
					PropertyUtils.setProperty(tarEntityPo, propertyName, null);
				}else{
					// 如果目标属性值为空，尝试用源属性值的主键来获取持久化对象，失败才新建
					String fkName = baseDao.getPkNameByEntityClass(fkEntityClass);
					Serializable fkId = fkDao.getPK(srcFkPropertyValue);
					if (tarFkPropertyValue==null){
						if (fkId!=null){
							tarFkPropertyValue = fkDao.getById(fkId, nextPropertyList);
							PropertyUtils.setProperty(tarEntityPo, propertyName, tarFkPropertyValue);
						}else{
							
						}
					}
					if (tarFkPropertyValue==null){
						log.debug("目标外键对象为空，如果除主键外还有持久化属性需要复制，则需要创建新的外键对象！");
						if (nextPropertyList!=null&&(","+nextPropertyList).contains(","+fkName)){
							// 剥离主键
							nextPropertyList = (","+nextPropertyList).replace(","+fkName, "");
							if (nextPropertyList.startsWith(",")){
								nextPropertyList = nextPropertyList.substring(1);
							}
						}
						if (nextPropertyList!=null&&nextPropertyList.length()>0){
							if (fkDao!=null){
								tarFkPropertyValue = fkDao.getNew();
								copyProperties(srcFkPropertyValue, tarFkPropertyValue, nextPropertyList, persistent, fkDao);
								tarFkPropertyValue = fkDao.save((T1)tarFkPropertyValue);
								// 已经是持久化对象了
								PropertyUtils.setProperty(tarEntityPo, propertyName, tarFkPropertyValue);
							}
						}
					}else{
						// 目标对象存在，简单的递归复制即可
						copyProperties(srcFkPropertyValue, tarFkPropertyValue, nextPropertyList, persistent, fkDao);
					}
				}
			}
		}else{
			// 该外键属性非持久化属性，需映射到其持久化属性上
			

			// 源属性非持久化属性，那么是否是集合呢
			if (propertyIsCollection){
				// 源属性非持久化属性，而且还是一个集合，如 department.users
				if (srcFkPropertyValue==null||((Collection<Object>)srcFkPropertyValue).size()==0){
					// 源属性非持久化属性，而且还是一个集合，源属性值为空, 那么持久化属性也应该是集合才对，应该将持久化集合删空
					if (tarFkPropertyValue!=null){
						// 目标属性不为空，如果目标属性允许为空，就直接赋值为空，否则就应该删除关联对象
						if (baseDao.isPropertyNonNull(persistencePropertyMemberClass, persistencePropertyName)){
							// 该属性不允许为空，删除关联对象
							persistenceEntityDao.delete(tarFkPropertyValue);
						}else{
							PropertyUtils.setProperty(persistenceEntity, persistencePropertyName, null);
						}
					}
				}else{
					// 源属性非持久化属性，而且还是一个集合，源属性值非空, 那么持久化属性列表中应删除不再有的，添加还没有的才对
					// 先保证持久化属性不为空
					if (persistencePropertyValue==null){
						persistencePropertyValue = new ArrayList<Object>();
						BeanUtilsExt.setPropertyValue(persistenceEntity, persistencePropertyName, persistencePropertyValue);
					}
					
					Set<Object> removeList = new HashSet<Object>();
					for(Object tarObj: (Collection<Object>)tarFkPropertyValue){
						removeList.add(tarObj);
					}
					List<Object> addList = new ArrayList<Object>();
					
					// 先删除没有的
					for(Object obj:(Collection<Object>)srcFkPropertyValue){
						
						Serializable srcFkId = fkDao.getPK(obj);
						if (srcFkId!=null){
							Object find = null;
							for(Object tarObj: (Collection<Object>)tarFkPropertyValue){
								Serializable fkId = (Serializable) BeanUtilsExt.getPropertyValue(tarObj, persistencePropertyName);
								if (fkId.equals(srcFkId)){
									find = tarObj;
									break;
								}
							}
							if (find == null){
								addList.add(obj);
							}else{
								removeList.remove(find);
							}
						}
					}
					
					// 那持久化属性就是外键对象吗
					if (!persistencePropertyMemberClass.equals(fkEntityClass)){
						// 源属性非持久化属性，而且还是一个集合，源属性值非空, 那么持久化属性列表中应删除不再有的，添加还没有的才对
						// 持久化属性就是外键对象
						
						
						
						IBaseDao<Object, Serializable> fkEntityDao = (IBaseDao<Object, Serializable>)baseDao.getBaseDao(fkEntityClass);
						if (fkEntityDao!=null){
							Serializable sourcePropertyPkId = fkEntityDao.getPK(srcFkPropertyValue);
							tarFkPropertyValue = PropertyUtils.getProperty(tarEntityPo, propertyName);
							Serializable targetPropertyPkId = null;
							if (tarFkPropertyValue!=null){
								targetPropertyPkId = fkEntityDao.getPK(tarFkPropertyValue);
							}
							if (sourcePropertyPkId!=null&&!sourcePropertyPkId.equals(targetPropertyPkId)){
								// 源属性有id，需要要替换目标对象及关联外键值
								BeanUtilsExt.setPropertyValue(persistenceEntity, persistencePropertyName, sourcePropertyPkId);
								tarFkPropertyValue = fkEntityDao.getById(sourcePropertyPkId, nextPropertyList);
								BeanUtilsExt.setPropertyValue(tarEntityPo, propertyName, tarFkPropertyValue);
							}
							if (tarFkPropertyValue==null){
								log.debug("目标外键对象为空，需要创建新的外键对象！");
								Object sourcePropertyId = PropertyUtils.getProperty(srcFkPropertyValue, baseDao.getPkNameByEntityClass(fkEntityClass));
								if (sourcePropertyId!=null){
									tarFkPropertyValue = fkEntityDao.getById((Serializable)sourcePropertyId, nextPropertyList);
									if (tarFkPropertyValue==null){
										tarFkPropertyValue = fkEntityDao.getNew();
									}

									copyProperties(srcFkPropertyValue, tarFkPropertyValue, nextPropertyList, persistent, fkEntityDao);
									tarFkPropertyValue = fkEntityDao.save((T1)tarFkPropertyValue);
									// 已经是持久化对象了,需要更新外键主键哦
									String fkName = PersistenceHelper.findForeignKey(propertyName, fkEntityClass, persistenceEntityDao.getForeignKeyMap()).getKey().split(":")[1];
									sourcePropertyId = PropertyUtils.getProperty(tarFkPropertyValue, baseDao.getPkNameByEntityClass(fkEntityClass));
									PropertyUtils.setProperty(tarFkPropertyValue, fkName, sourcePropertyId);
								}
							}else{
								// 目标对象存在，简单的递归复制即可
								if (nextPropertyList!=null&&nextPropertyList.length()>0){
									copyProperties(srcFkPropertyValue, tarFkPropertyValue, nextPropertyList, persistent, fkEntityDao);
									fkEntityDao.saveOrUpdate((T1)tarFkPropertyValue);
								}
							}
						}
					}else{
						// 源属性非持久化属性，而且还是一个集合，源属性值非空, 那么持久化属性列表中应删除不再有的，添加还没有的才对
						// 持久化属性不是外键对象，应就只是外键的键值
						dddd(srcEntityVo, baseDao, relevanceMap,
								entityClass, fkEntityClass,
								srcFkPropertyValue, tarFkPropertyValue,
								persistencePropertyName,
								persistencePropertyMemberClass,
								persistenceEntity, persistencePropertyValue);
					}
				}
			}else{
				// 源属性非持久化属性，但还不是集合，如 user.depart, user.userOrgs.deptId, user.userOrgs.depart,
				if (srcFkPropertyValue==null){
					// 源属性值为空, 持久化属性能否为空
					if (!persistenceEntityClass.equals(entityClass)){
						// 持久化类是一个中间类，通常是一个关系,如果这个属性不允许为空的话，就只有删除该关系对象
						if (baseDao.isPropertyNonNull(persistenceEntityClass, persistencePropertyName)){
							// 源属性值为空, 持久化属性不能为空
							persistenceEntityDao.delete(persistenceEntity);
						}else{
							// 源属性值为空, 持久化属性可以为空
							BeanUtilsExt.setPropertyValue(persistenceEntity, persistencePropertyName, null);
							persistenceEntityDao.update(persistenceEntity, persistencePropertyName);
							BeanUtilsExt.setPropertyValue(tarEntityPo, propertyName, null);
						}
					}
				}else{
					// 源属性值不为空, 持久化属性成员类型是否是目标类型呢？
					if (!persistencePropertyMemberClass.equals(fkEntityClass)){
						// 源属性不为空，持久化属性成员类型不是目标类型，应该是目标键值
						IBaseDao<Object, Serializable> fkEntityDao = (IBaseDao<Object, Serializable>)baseDao.getBaseDao(fkEntityClass);
						Serializable sourcePropertyPkId = fkEntityDao.getPK(srcFkPropertyValue);
						if (sourcePropertyPkId!=null){
							// 源外键属性如果带主键，以它为准
							BeanUtilsExt.setPropertyValue(persistenceEntity, persistencePropertyName, sourcePropertyPkId);
							tarFkPropertyValue = fkEntityDao.getById(sourcePropertyPkId);
							BeanUtilsExt.setPropertyValue(tarEntityPo, propertyName, tarFkPropertyValue);
						}
						if (nextPropertyList!=null&&nextPropertyList.length()>0){
							// 有下一级属性列表
							copyProperties(srcFkPropertyValue, tarFkPropertyValue, nextPropertyList, persistent, fkEntityDao);
						}
					}else{
						dddd(srcEntityVo, baseDao, relevanceMap,
								entityClass, fkEntityClass,
								srcFkPropertyValue, tarFkPropertyValue,
								persistencePropertyName,
								persistencePropertyMemberClass,
								persistenceEntity,
								persistencePropertyValue);
					}
				}
			}
		}
	}

	private static <T, PK extends Serializable, T1> void dddd(T srcPkEntityVo,
			IBaseDao<T, PK> baseDao, Map<String, String> relevanceMap,
			Class<T> pkEntityClass, Class<T1> fkEntityClass,
			Object srcPkFkPropertyValue, Object tarPkFkPropertyValue,
			String persistencePropertyName,
			Class<?> persistencePropertyMemberClass,
			Object persistenceEntityPo, Object persistencePropertyValue)
			throws Exception {
		// 源属性值不为空
		Serializable fkId = (Serializable)PropertyUtils.getProperty(srcPkFkPropertyValue, baseDao.getPkNameByEntityClass(fkEntityClass));
		// 目标属性不存在的话要新建该目标属性对象，并添加到持久化属性集合中
		IBaseDao<Object, Serializable> relationDao = (IBaseDao<Object, Serializable>)baseDao.getBaseDao(persistencePropertyMemberClass);
		if (relationDao!=null){
			Serializable pkId = baseDao.getPK(srcPkEntityVo);
			Entry<String, Class<?>> dd = PersistenceHelper.findForeignKey(persistencePropertyName, pkEntityClass, relationDao.getForeignKeyMap());
			String fkName2;
			if (dd!=null){
				fkName2 = dd.getKey().split(":")[1];
			}else{
				fkName2 = null;
			}
			if (tarPkFkPropertyValue==null){
				tarPkFkPropertyValue = relationDao.getNew();
				((Collection<Object>)persistencePropertyValue).add(tarPkFkPropertyValue);
				PropertyUtils.setProperty(tarPkFkPropertyValue, persistencePropertyName, fkId);
				// 无法保证能正确持久化，还是在先记录下来，在主键对象持久化完成后再检查，处理吧
				// 需要记录下属性名，如 userOrgs，
			}else{
				PropertyUtils.setProperty(persistenceEntityPo, persistencePropertyName, fkId);
			}
			if (!relevanceMap.containsKey(persistencePropertyName)){
				relevanceMap.put(persistencePropertyName, fkName2);
			}
		}
	}

	/**
	 * 获取持久化映射关系
	 * @param srcEntityVo
	 * @param tarEntityPo
	 * @param propertyName
	 * @param baseDao
	 * @param entityClass
	 * @param propertyMemberClass
	 * @param propertyIsCollection
	 * @return
	 * @throws NoSuchFieldException
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 * @throws NoSuchMethodException
	 * @throws Exception
	 */
	private static <T, PK extends Serializable> Map<String, Object> getPersistenceProperty(
			T srcEntityVo, T tarEntityPo, String propertyName, IBaseDao<T, PK> baseDao, 
			Class<?> fkPropertyClass, Class<?> fkEntityClass, boolean fkPropertyIsCollection, 
			Map<String, String> relevanceMap) throws Exception {
		
		Map<String, Object> result = null; 
		
		Entry<String, Class<?>> en2 = PersistenceHelper.findForeignKey(propertyName, fkEntityClass, baseDao.getForeignKeyMap());
		if (en2!=null){
			String[] persistencePropertyPath = en2.getKey().split(":")[1].split("\\.");
			if (persistencePropertyPath.length>0){
				result = new HashMap<String, Object>();
				
				Class<T> entityClass = baseDao.getEntityClass();
				
				Class<?> 	persistenceEntityClass 	= entityClass;
				Object 		persistenceEntity 		= tarEntityPo;								// 最终的持久化对象
				Serializable pkId = baseDao.getPK(tarEntityPo);
				boolean 	persistenceEntityIsCollection = false;
				
				Object srcFkPropertyValue = PropertyUtils.getProperty(srcEntityVo, propertyName);

				String persistencePropertyName = persistencePropertyPath[persistencePropertyPath.length-1];
				Class<?> persistencePropertyClass = null;
				Class<?> persistencePropertyMemberClass = null;
				boolean persistencePropertyIsCollection = false;
				Object persistencePropertyValue = null;
				
				// 迭代变量初始化
				// 主键对象或替代的持久化关联对象Dao
				IBaseDao<Object, Serializable> rkDao = (IBaseDao<Object, Serializable>)baseDao;
				
				Object		pkTargetPropertyMemberValue;
				
				IBaseDao<Object, Serializable> fkDao = null;
				
				for(int i = 0;i<persistencePropertyPath.length-1;i++){
					persistencePropertyName = persistencePropertyPath[i];
					
					persistencePropertyClass = BeanUtilsExt.getPropertyType(persistenceEntityClass, persistencePropertyName);
					if (Collection.class.isAssignableFrom(persistencePropertyClass)){
						persistencePropertyIsCollection = true;
						persistencePropertyMemberClass = BeanUtilsExt.getMemberType(persistenceEntityClass, persistencePropertyName);
					}else{
						persistencePropertyMemberClass = persistencePropertyClass;
					}
					
					if (rkDao.isPersistentProperty(persistencePropertyName)){
						// 这还差不多，真是持久化属性
						persistencePropertyValue = PropertyUtils.getProperty(persistenceEntity, persistencePropertyName);
						rkDao = (IBaseDao<Object, Serializable>)rkDao.getBaseDao(persistencePropertyMemberClass);
					}else{
						// 这个属性居然不是真正的持久化属性，那就得自行读取
						rkDao = (IBaseDao<Object, Serializable>)rkDao.getBaseDao(persistencePropertyMemberClass);
						PersistenceHelper.findForeignKey(persistencePropertyName, persistenceEntityClass, rkDao.getForeignKeyMap());
						/// 以后再说...
						throw new Exception("这个属性居然不是真正的持久化属性，那就得自行读取,  以后再说...");
						
					}

					// 中间级处理
					// 持久化属性在外键关联表对象上，比如 userDeptOrg，可能同时关联多个外键属性，应合并处理

					if (persistenceEntityIsCollection){
						// 前一级是集合
						
					}else{
						// 前一级不是集合，但这一级是不是呢？
						if (persistencePropertyIsCollection){
							// 前一级不是集合，但这一级属性是集合，看是否能有个唯一的值可以取
							
							// 先保证集合属性不为null
							if (persistencePropertyValue==null){
								persistencePropertyValue = new ArrayList<Object>();
								BeanUtilsExt.setPropertyValue(persistenceEntity, persistencePropertyName, persistencePropertyValue);
							}
							
							// 前一级不是集合，但这一级属性是集合，如果前一级为空，可能需要清空或删除集合，
							// 如果前一级不为空，必须要保证至少有一个成员
							if (persistenceEntity==null){
								// 前一级不是集合，但这一级属性是集合，而且前一级为空，需要清空或删除集合，
								for(Object obj:(Collection<Object>)persistencePropertyValue){
									rkDao.delete(obj);
								}
							}else{
								// 前一级不是集合，但这一级属性是集合，而且前一级不空，需要保证至少有一条记录，
								pkTargetPropertyMemberValue = null;
								if (((Collection<Object>)persistencePropertyValue).size()>0){
									for(Object obj:(Collection<Object>)persistencePropertyValue){
										if (obj!=null){
											pkTargetPropertyMemberValue = obj;
											break;
										}
									}
									pkTargetPropertyMemberValue = pkTargetPropertyMemberValue;
								}
								if (pkTargetPropertyMemberValue==null){
									// 得添加一条记录
									pkTargetPropertyMemberValue = rkDao.getNew();
									// 设置关联关系
									// 保存或添加到延迟保存表中
									((Collection<Object>)persistencePropertyValue).add(pkTargetPropertyMemberValue);
									String fkPropertyName = getFkPropertyName(persistenceEntityClass, persistencePropertyName, rkDao);
									if (pkId==null){
										relevanceMap.put(persistencePropertyName, fkPropertyName);
									}else{
										BeanUtilsExt.setPropertyValue(pkTargetPropertyMemberValue, fkPropertyName, pkId);
										rkDao.save(pkTargetPropertyMemberValue);
									}
								}else{
									// 有一条记录就好
									
								}
								// 就当它不是集合了
								persistencePropertyIsCollection = false;
								persistencePropertyValue = pkTargetPropertyMemberValue;
								
							}
						}else{
							// 前一级不是集合，但这一级也不是集合，简单
							
							// 源属性不是集合
							if (srcFkPropertyValue==null){
								// 
							}else{
								// 源属性值及要持久化的外键对象不为空，需要新建关联对象
								
							}
						}
					}
					persistenceEntityClass = persistencePropertyMemberClass;
					persistenceEntity = persistencePropertyValue;
					persistenceEntityIsCollection = fkPropertyIsCollection;
				}
				
				persistencePropertyName = persistencePropertyPath[persistencePropertyPath.length-1];

				result.put("persistenceEntityClass", 			persistenceEntityClass);			// 最终的持久化实体类型
				result.put("persistenceEntity", 				persistenceEntity);				// 最终的持久化对象
				result.put("persistencePropertyName",			persistencePropertyName);			// 持久化属性名
			}
		}
		
		return result;
	}

	private static String getFkPropertyName(Class<?> persistenceEntityClass,
			String persistencePropertyName, IBaseDao<Object, Serializable> rkDao) {
		String fkPropertyName = null;

		Entry<String, Class<?>> en3 = PersistenceHelper.findForeignKey(persistencePropertyName, persistenceEntityClass, rkDao.getForeignKeyMap());
		if (en3!=null){
			fkPropertyName = en3.getKey().split(":")[1];
		}
		return fkPropertyName;
	}

	/**
	 * 先复制简单属性，并过滤出外键属性及其属性列表
	 * @param srcEntityVo
	 * @param tarEntityPo
	 * @param copyPropertyList
	 * @param baseDao
	 * @param entityClass
	 * @return
	 * @throws NoSuchFieldException
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 * @throws NoSuchMethodException
	 */
	private static <T, PK extends Serializable> Map<String, String> firstCopySimpleProperties(
			T srcEntityVo, T tarEntityPo, String copyPropertyList,
			IBaseDao<T, PK> baseDao)
			throws NoSuchFieldException, IllegalAccessException,
			InvocationTargetException, NoSuchMethodException {
		Map<String, String> propertyMap = new HashMap<String, String>();
		
		Class<T> entityClass = baseDao.getEntityClass();
		String[] fields = copyPropertyList.split(",");
		for (String property : fields) {
			if (property!=null&&property.length()>1){
				String[] propertyArray = property.split("\\.");
				if (propertyArray.length>0){
					// 当前处理的属性名
					String propertyName;
					// 持久化属性名
					String nextPropertyList;
					propertyName = propertyArray[0];
					if (propertyName.length()>0){
						if (propertyArray.length>1){
							// 有点分隔符，应该是外键对象，先记录下来，然后收集外键对象的属性列表
							// 属性遍历完成后再统一处理
							if (propertyMap.containsKey(propertyName)){
								// 已有过
								nextPropertyList = propertyMap.get(propertyName);
							}else{
								// 没有过，占个位置
								nextPropertyList = "";
							}
							
							// 生成外键对象属性，可以包括外键的外键描述
							String nextProperty = getNextPropertyList(propertyArray);
							// 记录外键对象的属性
							if (nextPropertyList==null||nextPropertyList.length()==0){
								nextPropertyList = "";
							}
							if (!(","+nextPropertyList+",").contains(","+nextProperty+",")){
								if (nextPropertyList.length()>0){
									nextPropertyList += ",";
								}
								nextPropertyList +=nextProperty;
							}
							propertyMap.put(propertyName, nextPropertyList);
							// 好了
							
						}else{
							// 简单的属性名，可以直接处理吧？看看是什么类型的值
							Class<?> valueClass = BeanUtilsExt.getPropertyType(entityClass, propertyName);
							if (Collection.class.isAssignableFrom(valueClass)){
								valueClass = BeanUtilsExt.getMemberType(entityClass, propertyName);
							}
							if (baseDao.isEntity(valueClass)){
								// 肯定是外键对象
								if (propertyMap.containsKey(propertyName)){
									// 已有过
									nextPropertyList = propertyMap.get(propertyName);
								}else{
									// 没有过，占个位置
									nextPropertyList = "";
								}
								
								// 生成外键对象属性，可以包括外键的外键描述
								String nextProperty = getNextPropertyList(propertyArray);
								// 记录外键对象的属性
								if (nextPropertyList==null||nextPropertyList.length()==0){
									nextPropertyList = "";
								}
								if (nextProperty!=null&&!(","+nextPropertyList+",").contains(","+nextProperty+",")){
									if (nextPropertyList.length()>0){
										nextPropertyList += ",";
									}
									nextPropertyList +=nextProperty;
								}
								propertyMap.put(propertyName, nextPropertyList);
							}else{
								// 不是实体对象, 那就应该是普通的值对象，直接处理了，如parentId，应该是持久化属性，暂不考虑非持久化属性
								// 如 department 的 level
								Object sourcePropertyValue = PropertyUtils.getProperty(srcEntityVo, propertyName);
								PropertyUtils.setProperty(tarEntityPo, propertyName, sourcePropertyValue);
							}
						}
					}
				}
			}
		}
		return propertyMap;
	}

	private static String getNextPropertyList(String[] propertyArray) {
		String nextProperty = null;
		for(int i=1;i<propertyArray.length;i++){
			if (nextProperty==null){
				nextProperty = "";
			}else{
				nextProperty += ".";
			}
			nextProperty += propertyArray[i];
		}
		return nextProperty;
	}
	
	public static Entry<String, Class<?>> findForeignKey(String propertyName, Class<?> clazz, Map<String, Class<?>> foreignKeyMap) {
		Entry<String, Class<?>> result = null;
		
		for(Entry<String, Class<?>> entry: foreignKeyMap.entrySet()){
			if (entry.getValue().equals(clazz)){
				String[] keyStr = entry.getKey().split(":");
				if (keyStr.length>0&&keyStr[0].equals(propertyName)||keyStr.length>2&&keyStr[2].equals(propertyName)){
					result = entry;
				}
			}
		}
		
		return result;
	}

}
